package aduros.game {

import flash.events.TimerEvent;
import flash.utils.Dictionary;
import flash.utils.Timer;

import com.threerings.util.Log;

import com.whirled.net.*;

import aduros.util.F;

/** Schedules jobs to be run at certain times or days, like a cron. */
/** !!! WARNING: Probably broken !!! */
public class Scheduler
{
    public static const PROP_LAST_ACTIVITY :String = NetConstants.makePersistent("aduros:cronStamp");

    public static const log :Log = Log.getLog(Scheduler);

    public function Scheduler (ctrl :PropertySubControl, jobs :Array) :void
    {
        _ctrl = ctrl;
        _jobs = jobs;
        _timers = new Dictionary();
        for (var ii :int = 0; ii < _jobs.length; ++ii) {
            startTimer(ii);
        }

        stamp();
    }

    protected function startTimer (jobId :int) :void
    {
        var job :Job = _jobs[jobId];
        var stamp :Date = getStamp();
        var now :Date = new Date();
        var timeUntil :Number = job.timeUntil(now);

        log.info("startTimer", "jobId", jobId, "timeUntil", timeUntil, "now", now.time, "stamp", stamp.time);

        if (stamp != null && now.time - stamp.time > timeUntil) {
            // We slept in
            runJob(jobId);
            trace("A");
        } else {
            var timer :Timer = new Timer(timeUntil);
            timer.addEventListener(TimerEvent.TIMER, F.callback(runJob, jobId));
            timer.start();
            _timers[jobId] = timer;
            trace("B");
        }
    }

    protected function runJob (jobId :int) :void
    {
        var job :Job = _jobs[jobId];
        try {
            job.func();
        } catch (error :*) {
            log.error("Error calling job", "error", error);
        }

        if (jobId in _timers) {
            Timer(_timers[jobId]).stop();
        }
        stamp();
        startTimer(jobId);
    }

    protected function stamp () :void
    {
        trace("STAMP");
        _ctrl.set(PROP_LAST_ACTIVITY, new Date().time, true);
    }

    protected function getStamp () :Date
    {
        var time :Number = _ctrl.get(PROP_LAST_ACTIVITY) as Number;
        return (time > 0) ? new Date(time) : null;
    }

    public function stop () :void
    {
        for each (var timer :Timer in _timers) {
            timer.stop();
        }
        _timers = null;
        _jobs = null;
    }

    protected var _ctrl :PropertySubControl;
    protected var _jobs :Array;
    protected var _timers :Dictionary;
}

}
